/*
package com.minidb.engine;

import com.minidb.storage.BufferPool;
import com.minidb.storage.FileManager;
import com.minidb.storage.Page;
import com.minidb.utils.Condition;

import java.util.ArrayList;
import java.util.List;

*/
/**
 * StorageEngine
 * - 对上提供基于表的插入/查询/删除接口
 * - 对下使用 FileManager + BufferPool + Page（页式持久化 + 缓存）
 * - NEW: 遍历/定位页面改为按 FileManager.listPageIds()；页被清空后释放并加入空闲页清单
 *//*

public class StorageEngine {
    private final BufferPool bufferPool;
    private final FileManager fileManager;
    private final CatalogManager catalogManager;

    public StorageEngine(BufferPool bufferPool, FileManager fileManager, CatalogManager catalogManager) {
        this.bufferPool = bufferPool;
        this.fileManager = fileManager;
        this.catalogManager = catalogManager;
    }

    */
/** 插入一条记录（values），返回 1=成功，0=失败 *//*

    public int insertRecord(String tableName, List<String> values, List<String> columnOrder) {
        // 保证至少有一页：若没有现存页 → 分配
        if (fileManager.listPageIds(tableName).isEmpty()) {
            Page newPage = fileManager.allocatePage(tableName);
            bufferPool.putPage(tableName, newPage);
        }

        // 获取“最后一页”（按实际存在的最大页号）
        int lastPageId = fileManager.getLastPageId(tableName);
        Page page = bufferPool.getPage(tableName, lastPageId);

        // 如果最后一页满了，分配新页
        if (pageAddWouldFail(page)) {
            Page newPage = fileManager.allocatePage(tableName);
            bufferPool.putPage(tableName, newPage);
            page = newPage;
        }

        // 根据 schema 重排列（如果提供了 columnOrder）
        List<String> toWrite;
        if (columnOrder != null && !columnOrder.isEmpty()) {
            List<String> schema = catalogManager.getColumns(tableName);
            toWrite = new ArrayList<>(schema.size());
            for (int i = 0; i < schema.size(); i++) toWrite.add("");
            for (int i = 0; i < columnOrder.size(); i++) {
                int idx = schema.indexOf(columnOrder.get(i));
                toWrite.set(idx, values.get(i));
            }
        } else {
            toWrite = new ArrayList<>(values);
        }

        boolean ok = page.addRecord(toWrite);
        return ok ? 1 : 0;
    }

    */
/** 全表扫描（返回所有记录的副本） *//*

    public List<List<String>> selectAllRecords(String tableName) {
        List<List<String>> out = new ArrayList<>();
        for (int pid : fileManager.listPageIds(tableName)) {
            Page p = bufferPool.getPage(tableName, pid);
            for (List<String> rec : p.getRecords()) out.add(new ArrayList<>(rec));
        }
        return out;
    }

    */
/** 条件删除，返回删除条数；页被清空时释放（加入空闲页清单） *//*

    public int deleteRecords(String tableName, Condition cond) {
        int del = 0;
        List<Integer> pageIds = new ArrayList<>(fileManager.listPageIds(tableName)); // 避免遍历中修改
        for (int pid : pageIds) {
            Page p = bufferPool.getPage(tableName, pid);
            if (cond == null) {
                int c = p.getRecords().size();
                if (c > 0) {
                    p.getRecords().clear();
                    p.setDirty(true);
                    del += c;
                }
                // 整页无记录 → 释放到空闲页
                fileManager.freePage(tableName, pid);
            } else {
                var recs = p.getRecords();
                int before = recs.size();
                recs.removeIf(r -> catalogManager.evaluateCondition(tableName, cond, r));
                int after = recs.size();
                if (after < before) {
                    p.setDirty(true);
                    del += (before - after);
                }
                // 条件删除后若页被清空 → 释放到空闲页
                if (recs.isEmpty()) {
                    // 先把当前脏页写回清空状态（可选），随后释放
                    bufferPool.flushPage(tableName, pid);
                    fileManager.freePage(tableName, pid);
                }
            }
        }
        return del;
    }

    // —— 辅助：以当前页能否再插入来近似判断“页满” —— //
    private boolean pageAddWouldFail(Page p) {
        List<String> tiny = List.of("x"); // 简易估计
        boolean ok = p.addRecord(tiny);
        if (ok) {
            p.getRecords().remove(p.getRecords().size() - 1);
            p.setDirty(false);
        }
        return !ok;
    }
}
*/

package com.minidb.engine;

import com.minidb.storage.BufferPool;
import com.minidb.storage.FileManager;
import com.minidb.storage.Page;
import com.minidb.utils.Condition;

import java.util.ArrayList;
import java.util.List;

/**
 * StorageEngine
 * - 使用 FileManager + BufferPool
 * - NEW: 遍历页按 FileManager.listPageIds()
 * - NEW: insert 优先复用 free list（FileManager.allocatePage 已实现复用）
 * - NEW: delete 后若页被清空则 freePage（写回并从文件系统删除）
 */
public class StorageEngine {
    private final BufferPool bufferPool;
    private final FileManager fileManager;
    private final CatalogManager catalogManager;

    public StorageEngine(BufferPool bufferPool, FileManager fileManager, CatalogManager catalogManager) {
        this.bufferPool = bufferPool;
        this.fileManager = fileManager;
        this.catalogManager = catalogManager;
    }

    /** 插入一条记录（values），返回 1=成功，0=失败 */
    /** 插入一条记录（values），返回 1=成功，0=失败 */
    public int insertRecord(String tableName, List<String> values, List<String> columnOrder) {
        // 添加表存在性检查
        if (!catalogManager.tableExists(tableName)) {
            return 0; // 表不存在，返回失败
        }
        
        // 如果表没有任何页，则 allocatePage（FileManager 优先复用 free list）
        if (fileManager.listPageIds(tableName).isEmpty()) {
            Page p = fileManager.allocatePage(tableName);
            bufferPool.putPage(tableName, p);
        }

        // 获取最后一页 id
        int lastPageId = fileManager.getMaxPageId(tableName);
        Page page = bufferPool.getPage(tableName, lastPageId);

        if (pageAddWouldFail(page)) {
            Page newPage = fileManager.allocatePage(tableName);
            bufferPool.putPage(tableName, newPage);
            page = newPage;
        }

        // 重排列
        List<String> toWrite;
        if (columnOrder != null && !columnOrder.isEmpty()) {
            List<String> schema = catalogManager.getColumns(tableName);
            toWrite = new ArrayList<>(schema.size());
            for (int i = 0; i < schema.size(); i++) toWrite.add("");
            for (int i = 0; i < columnOrder.size(); i++) {
                int idx = schema.indexOf(columnOrder.get(i));
                toWrite.set(idx, values.get(i));
            }
        } else {
            toWrite = new ArrayList<>(values);
        }

        boolean ok = page.addRecord(toWrite);
        return ok ? 1 : 0;
    }

    /** 全表扫描 */
    public List<List<String>> selectAllRecords(String tableName) {
        List<List<String>> out = new ArrayList<>();
        for (int pid : fileManager.listPageIds(tableName)) {
            Page p = bufferPool.getPage(tableName, pid);
            for (List<String> rec : p.getRecords()) out.add(new ArrayList<>(rec));
        }
        return out;
    }

    /** 删除记录；若页被清空则释放该页（加入 free list） */
    public int deleteRecords(String tableName, Condition cond) {
        int del = 0;
        List<Integer> pageIds = new ArrayList<>(fileManager.listPageIds(tableName)); // 复制以免遍历修改
        for (int pid : pageIds) {
            Page p = bufferPool.getPage(tableName, pid);
            if (cond == null) {
                int c = p.getRecords().size();
                if (c > 0) {
                    p.getRecords().clear();
                    p.setDirty(true);
                    del += c;
                }
                // 释放页到 free list
                bufferPool.flushPage(tableName, pid); // 把清空后的页写回（将变成空页文件或已删除）
                fileManager.freePage(tableName, pid);
            } else {
                var recs = p.getRecords();
                int before = recs.size();
                recs.removeIf(r -> catalogManager.evaluateCondition(tableName, cond, r));
                int after = recs.size();
                if (after < before) {
                    p.setDirty(true);
                    del += (before - after);
                }
                if (recs.isEmpty()) {
                    bufferPool.flushPage(tableName, pid);
                    fileManager.freePage(tableName, pid);
                }
            }
        }
        return del;
    }

    private boolean pageAddWouldFail(Page p) {
        List<String> tiny = List.of("x");
        boolean ok = p.addRecord(tiny);
        if (ok) {
            p.getRecords().remove(p.getRecords().size() - 1);
            p.setDirty(false);
        }
        return !ok;
    }
}
